using System;

namespace Quiki.ExpressionParsers
{
    public class BinaryWikiTokenInlineExpressionParser : IWikiInlineExpressionParser
    {
        public BinaryWikiTokenInlineExpressionParser(string token, WikiTextElementType wikiTextElementType)
        {
            startingToken = token;
            endingToken = token;
            elementType = wikiTextElementType;
        }

        public BinaryWikiTokenInlineExpressionParser (
            string startingToken,
            string endingToken,
            WikiTextElementType wikiTextElementType)
        {
            this.startingToken = startingToken;
            this.endingToken = endingToken;
            this.elementType = wikiTextElementType;
        }

        public BinaryWikiTokenInlineExpressionParser (
            string startingToken, 
            string endingToken,
            Func<string, WikiTextElement> elementConstructor)
        {
            this.startingToken = startingToken;
            this.endingToken = endingToken;
            this.elementConstructor = elementConstructor;
        }

        public void Process (WikiTextElement element)
        {
            if (element.Terminal)
                return;

            if (element.Text == null)
            {
                foreach (WikiTextElement childElement in element.ChildElements)
                    Process(childElement);
                return;
            }

            int index = 0;
            bool inToken = false;

            while (true)
            {
                string token = inToken ? endingToken : startingToken;

                int find = element.Text.IndexOf(token, index, StringComparison.Ordinal);
                if (find == -1)
                    break;

                if (inToken)
                {
                    CreateWikiTextElementFromTextPortion (element, index, find, null);
                    inToken = false;
                }
                else
                {
                    CreateWikiTextElementFromTextPortion(element, index, find, WikiTextElementType.Text);
                    inToken = true;
                }

                index = find + token.Length;
            }

            if (index > 0)
            {
                CreateWikiTextElementFromTextPortion(element, index, element.Text.Length, WikiTextElementType.Text);
                element.Text = null;
            }
        }

        private void CreateWikiTextElementFromTextPortion (
            WikiTextElement parentElement,
            int startIndex,
            int endIndex,
            WikiTextElementType? newElementType)
        {
            int length = endIndex - startIndex;
            if (length == 0)
                return;

            string elementText = parentElement.Text.Substring (startIndex, length);

            WikiTextElement element;
            if (newElementType.HasValue)
                element = new WikiTextElement (newElementType.Value, elementText);
            else if (elementConstructor != null)
                element = elementConstructor (elementText);
            else
                element = new WikiTextElement (elementType, elementText);

            parentElement.ChildElements.Add (element);
        }

        private readonly string startingToken;
        private readonly string endingToken;
        private readonly Func<string, WikiTextElement> elementConstructor;
        private readonly WikiTextElementType elementType;
    }
}